package com.ty.user.starter.util;

import com.ty.user.starter.exception.UserMgtException;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.util.Base64;

@Slf4j
public class RSAUtil {
    private RSAUtil() {
    }

    /**
     * 指定算法
     */
    private static final String RSA = "RSA";

    /**
     * 生成RSA密钥对
     */
    public static KeyPair generateRSAKey() throws UserMgtException {
        KeyPairGenerator keyPairGen;
        try {
            keyPairGen = KeyPairGenerator.getInstance(RSA);
        } catch (NoSuchAlgorithmException e) {
            throw new UserMgtException("当前环境不支持生成RSA算法");
        }
        keyPairGen.initialize(2048);
        return keyPairGen.generateKeyPair();
    }


    /**
     * 加密
     *
     * @param data 明文
     * @param key  密钥
     * @return 数据
     */
    public static byte[] encrypt(byte[] data, Key key) throws UserMgtException {
        return cipher(Cipher.ENCRYPT_MODE, data, key);
    }

    private static byte[] cipher(int mode, byte[] data, Key key) throws UserMgtException {
        Cipher cipher;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new UserMgtException("当前环境不支持生成RSA算法");
        }

        try {
            cipher.init(mode, key);
        } catch (InvalidKeyException e) {
            throw new UserMgtException("key无效");
        }

        try {

            return cipher.doFinal(data);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new UserMgtException("数据错误，加解密失败");
        }
    }

    /**
     * 解密
     *
     * @param data 密文
     * @param key  密钥
     * @return 明文
     */
    public static byte[] decrypt(byte[] data, Key key) throws UserMgtException {
        return cipher(Cipher.DECRYPT_MODE, data, key);
    }

    public static String encodeBase64(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static byte[] decodeBase64(String base64) {
        return Base64.getDecoder().decode(base64);
    }

}
